import fs from 'node:fs';
import crypto from 'node:crypto';
import { gzip, gunzip } from 'node:zlib';
import path from 'node:path';
import { networkInterfaces } from 'node:os';
import { log } from '@common/utils/';

export const joinPath = (...paths: string[]): string => path.join(...paths);

export const extname = (p: string): string => path.extname(p);
export const basename = (p: string, ext?: string): string => path.basename(p, ext);
export const dirname = (p: string): string => path.dirname(p);

/**
 * 检查路径是否存在
 * @param {*} path 路径
 */
export const checkPath = async (path: string): Promise<boolean> => {
  return new Promise((resolve) => {
    if (!path) {
      resolve(false);
      return;
    }
    fs.access(path, fs.constants.F_OK, (err) => {
      if (err) {
        resolve(false);
        return;
      }
      resolve(true);
    });
  });
};

export const getFileStats = async (path: string): Promise<fs.Stats | null> => {
  return new Promise((resolve) => {
    if (!path) {
      resolve(null);
      return;
    }
    fs.stat(path, (err, stats) => {
      if (err) {
        resolve(null);
        return;
      }
      resolve(stats);
    });
  });
};

/**
 * 检查路径并创建目录
 * @param path
 * @returns
 */
export const createDir = async (path: string) =>
  new Promise<void>((resolve, reject) => {
    fs.access(path, fs.constants.F_OK | fs.constants.W_OK, (err) => {
      if (err) {
        if (err.code === 'ENOENT') {
          fs.mkdir(path, { recursive: true }, (err) => {
            if (err) {
              reject(err);
              return;
            }
            resolve();
          });
          return;
        }
        reject(err);
        return;
      }
      resolve();
    });
  });

export const removeFile = async (path: string) =>
  new Promise<void>((resolve, reject) => {
    fs.access(path, fs.constants.F_OK, (err) => {
      if (err) {
        err.code == 'ENOENT' ? resolve() : reject(err);
        return;
      }
      fs.unlink(path, (err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve();
      });
    });
  });

export const readFile = async (path: string) => fs.promises.readFile(path);

/**
 * 创建 MD5 hash
 * @param {*} str
 */
export const toMD5 = (str: string) => crypto.createHash('md5').update(str).digest('hex');

export const gzipData = async (str: string): Promise<Buffer> => {
  return new Promise((resolve, reject) => {
    gzip(str, (err, result) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(result);
    });
  });
};

export const gunzipData = async (buf: Buffer): Promise<string> => {
  return new Promise((resolve, reject) => {
    gunzip(buf, (err, result) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(result.toString());
    });
  });
};

export const saveStrToFile = async (path: string, str: string | Buffer): Promise<void> => {
  await new Promise<void>((resolve, reject) => {
    fs.writeFile(path, str, (err) => {
      if (err) {
        log.error(err);
        reject(err);
        return;
      }
      resolve();
    });
  });
};

export const b64DecodeUnicode = (str: string): string => {
  // Going backwards: from bytestream, to percent-encoding, to original string.
  // return decodeURIComponent(window.atob(str).split('').map(function(c) {
  //   return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
  // }).join(''))

  return Buffer.from(str, 'base64').toString();
};

export const copyFile = async (sourcePath: string, distPath: string) => {
  return fs.promises.copyFile(sourcePath, distPath);
};

export const moveFile = async (sourcePath: string, distPath: string) => {
  return fs.promises.rename(sourcePath, distPath);
};

export const getAddress = (): string[] => {
  const nets = networkInterfaces();
  const results: string[] = [];
  // console.log(nets)

  for (const interfaceInfos of Object.values(nets)) {
    if (!interfaceInfos) continue;
    // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
    for (const interfaceInfo of interfaceInfos) {
      if (interfaceInfo.family === 'IPv4' && !interfaceInfo.internal) {
        results.push(interfaceInfo.address);
      }
    }
  }
  return results;
};
